package yunquan.wang.base.dao;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;

import org.apache.commons.lang3.StringUtils;
import org.springframework.data.jpa.domain.Specification;

import yunquan.wang.base.utils.ConvertUtils;

@SuppressWarnings(value = { "unchecked", "rawtypes" })
public class DaoUtils {
	

 //	EQ, LIKE, LT, GT, LE, GE,NOT,IN,SQL;
	/**
	 * 相等
	 * @param <T>
	 * @param propertyName
	 * @param value
	 * @return
	 */
	public static   Specification  eq(final String propertyName, final Object value) {
		return new Specification() {
			public Predicate toPredicate(Root root, CriteriaQuery query,
					CriteriaBuilder cb) {
				Path path=toExpressionRecursively(root, propertyName);
				return cb.equal( path, convertValue(path,value));
			}
		};
	}
	/**
	 * Exist 子查询
	 * @param propertyName
	 * @param value
	 * @param clazz
	 * @return
	 */
	public static   Specification  exist(final String propertyName, final Object value,final Class clazz) {
		return new Specification() {
			public Predicate toPredicate(Root root, CriteriaQuery query,
					CriteriaBuilder cb) {
				//子查询
				Subquery subquery=	query.subquery(clazz);
				Root fromProject = subquery.from(clazz);
				subquery.select(fromProject.get("id"));
				Path path=toExpressionRecursively(root, propertyName);
				subquery.where(cb.equal(path,convertValue(path,value)));
	 	return	cb.exists(subquery);
	 
			}
		};
	}
	/**
	 *不相等
	 * @param propertyName
	 * @param value
	 * @return
	 */
	public static Specification ne(final String propertyName, final Object value) {
		return new Specification() {
			public Predicate toPredicate(Root root, CriteriaQuery query,
					CriteriaBuilder cb) {
				Path path=toExpressionRecursively(root, propertyName);
				return cb.notEqual( path, convertValue(path,value));
			}
		};
	}
	/**
	 * 抓取关联属性
	 * @param porpertyName
	 * @return
	 */
	public static Specification fetch(final String porpertyName)
	{
		return new Specification() {	public Predicate toPredicate(Root root, CriteriaQuery query,CriteriaBuilder cb) {
			 root.fetch(porpertyName);
	         return null;
			}
		};
	}
	
	
	/**
	 * 模糊查找
	 * 
	 * @param propertyName
	 * @param value
	 * @return
	 */
	public static Specification like(final String propertyName,
			final Object value) {
		return new Specification() {
			public Predicate toPredicate(Root root, CriteriaQuery query,
					CriteriaBuilder cb) {
				Path path=toExpressionRecursively(root, propertyName);
				return cb.like(path,
						String.format("%%%s%%", convertValue(path,value)));
			}
		};
	}
/**
 * 
 * @param propertyName
 * @param value
 * @return
 */
	public static   Specification gt(final String propertyName, final Object value) {
		return new Specification() {
			public Predicate toPredicate(Root root, CriteriaQuery query,
					CriteriaBuilder cb) {
				Path path=toExpressionRecursively(root, propertyName);
				return cb.greaterThan(path, (Comparable)convertValue(path,value));
			}
		};
	}
	
	/**
	 * 
	 * @param propertyName
	 * @param value
	 * @return
	 */
		public static   Specification lt(final String propertyName, final Object value) {
			return new Specification() {
				public Predicate toPredicate(Root root, CriteriaQuery query,
						CriteriaBuilder cb) {
					Path path=toExpressionRecursively(root, propertyName);
					return cb.lessThan(toExpressionRecursively(root, propertyName),(Comparable)convertValue(path,value));
				}
			};
		}
		
		
		/**
		 * 
		 * @param propertyName
		 * @param value
		 * @return
		 */
			public static   Specification ge(final String propertyName, final Object value) {
				return new Specification() {
					public Predicate toPredicate(Root root, CriteriaQuery query,
							CriteriaBuilder cb) {
						Path path=toExpressionRecursively(root, propertyName);
						return cb.greaterThanOrEqualTo(path,(Comparable)convertValue(path,value));
					}
				};
			}
			
		
			/**
			 * 
			 * @param propertyName
			 * @param value
			 * @return
			 */
				public static   Specification le(final String propertyName, final Object value) {
					return new Specification() {
						public Predicate toPredicate(Root root, CriteriaQuery query,
								CriteriaBuilder cb) {
							Path path=toExpressionRecursively(root, propertyName);
							return cb.lessThanOrEqualTo(path,(Comparable)convertValue(path,value));
						}
					};
				}
				
				/**
				 * 
				 * @param propertyName
				 * @param value
				 * @return
				 */
					public static   Specification notin(final String propertyName, final Object value) {
						return new Specification() {
							public Predicate toPredicate(Root root, CriteriaQuery query,
									CriteriaBuilder cb) {
								Path path=toExpressionRecursively(root, propertyName);
								return cb.isNotMember(value, path);
							}
						};
					}
					
					
					
					
					/**
					 * 
					 * @param propertyName
					 * @param value
					 * @return
					 */
						public static   Specification in(final String propertyName, final Object value) {
							return new Specification() {
								public Predicate toPredicate(Root root, CriteriaQuery query,
										CriteriaBuilder cb) {
									Path path=toExpressionRecursively(root, propertyName);
									return cb.isMember(value, path);
								}
							};
						}
					
					
						
						/**
						 * 
						 * @param propertyName
						 * @param value
						 * @return
						 */
							public static   Specification isnull(final String propertyName) {
								return new Specification() {
									public Predicate toPredicate(Root root, CriteriaQuery query,
											CriteriaBuilder cb) {
										Path path=toExpressionRecursively(root, propertyName);
										return cb.isNull(path);
									}
								};
							}
						
							
							/**
							 * 
							 * @param propertyName
							 * @param value
							 * @return
							 */
								public static   Specification notnull(final String propertyName) {
									return new Specification() {
										public Predicate toPredicate(Root root, CriteriaQuery query,
												CriteriaBuilder cb) {
											Path path=toExpressionRecursively(root, propertyName);
											return cb.isNotNull(path);
										}
									};
								}
								
							
	/**
	 * 解决多级级联的问题						
	 * @param path
	 * @param propertyName
	 * @return
	 */
	public static <T> Path<T> toExpressionRecursively(
			Path<T> root, String propertyName) {
		String[] names = StringUtils.split(propertyName, ".");
		Path expression = root.get(names[0]);
		for (int i = 1; i < names.length; i++) {
			expression = expression.get(names[i]);
		}
		return expression;
	}
	
	private static Object convertValue(Path expression ,Object orgValue)
	{
		Class attributeClass = expression.getJavaType();
		if (!attributeClass.equals(String.class)
				&& orgValue instanceof String) {
			return ConvertUtils.convert(orgValue,
					attributeClass);
		}
		return orgValue;
	}
}
